/*
 * ModelAdapter.java
 *
 * Created on 22 February 2005, 18:27
 */

package org.datamining.guha.rule;

import java.util.List;
import java.util.ArrayList;
//import org.apache.commons.logging.*;

import org.datamining.guha.association.FundedAssociation;
import org.datamining.guha.association.FundedImplication;
import org.datamining.guha.model.literal.Literal;
import org.datamining.guha.model.literal.LiteralFactory;


/**
 * This class should server as a communicator between
 * model (individual Literals) and user problem domain (general Items).
 *
 * @author Lukas Vlcek
 */
public class ModelAdapter {
    
    private List<Item> items;
    private int[] antecedentClasses;
    private int[] succedentClasses;
    //private Log log;
    
    /** Creates a new instance of ModelAdapter */
    public ModelAdapter(int numberOfAtomicLiterals, int[] classes) {
        items = new ArrayList<Item>();
        //log = LogFactory.getLog(getClass());
        initialize(numberOfAtomicLiterals, classes);
    }
    
    /** @return Item at given position */
    public Item getItem(int index) {
        return (Item) items.get(index);
    }
    
    /**
     * For example:
     * @param numberOfAtomicLiterals = 14
     * @param classes = [3,3,6,2]
     */
    private void initialize(int numberOfAtomicLiterals, int[] classes) {
        int sum = 0;
        for (int i = 0; i < classes.length; i++) {
            sum += classes[i];
        }
        if (sum != numberOfAtomicLiterals) {
            throw new RuntimeException("Invalid initialization: sum != numberOfAtomicLiterals");
        }
        
        LiteralFactory literalFactory = LiteralFactory.getInstance();
        
        int A = 65;
        for (int i = 0; i < classes.length; i++) {
            int classWidth = classes[i];
            if (classWidth > 0) {
                Item item = new Item("item"+i, classWidth);
                for (int j = 0; j < classWidth; j++) {
                    //Literal pl = literalFactory.getLiteral(new Literal(A + i,false));
                    //Literal nl = literalFactory.getLiteral(new Literal(A + i,true));
                    Literal pl = literalFactory.getLiteral(A + i,false);
                    Literal nl = literalFactory.getLiteral(A + i,true);
                    int pos = j*2;
                    item.getIntervalLiterals()[pos] = pl;
                    item.getIntervalLiterals()[pos+1] = nl;
                    item.getIntervalNames()[pos] = pl.toString();
                    item.getIntervalNames()[pos+1] = nl.toString();
                    if (j < classWidth - 1) { A++; }
                }
                items.add(item);
            }
        }
    }
    
    /**
     * @param classes int[] Order number of items which are antecedents
     */
    public void setAntecedent(int[] classes) {
        antecedentClasses = classes;
    }
    
    /**
     * @param classes int[] Order number of items which are succedents
     */
    public void setSuccedent(int[] classes) {
        succedentClasses = classes;
    }
    
    /**
     * @param lit Literal from FrequencyOrderedList
     * @return boolean = true if this Literal belongs to Item from Antecedent.
     */
    public boolean isAntecedent(Literal lit) {
        for (int itm = 0; itm < items.size(); itm++) {
            Item item = (Item) items.get(itm);            

            Literal[] litArray = item.getIntervalLiterals();
            for (int l = 0; l < litArray.length; l++) {
                if (lit == litArray[l]) {
                    // we have found Literal
                    // now we need to check if variable lit is stored in antecedentClasses[]
                    for (int x = 0; x < antecedentClasses.length; x++) {
                        if (antecedentClasses[x] == itm) {
                            return true;
                        }
                    }
                }
            }

        }
        return false;
    }
    
    /**
     * @param lit Literal from FrequencyOrderedList
     * @return boolean = true if this Literal belongs to Item from Succedent.
     */
    public boolean isSuccedent(Literal lit) {
        for (int itm = 0; itm < items.size(); itm++) {
            Item item = (Item) items.get(itm);            

            Literal[] litArray = item.getIntervalLiterals();
            for (int l = 0; l < litArray.length; l++) {
                if (lit == litArray[l]) {
                    // we have found Literal
                    // now we need to check if variable lit is stored in succedentClasses[]
                    for (int x = 0; x < succedentClasses.length; x++) {
                        if (succedentClasses[x] == itm) {
                            return true;
                        }
                    }
                }
            }

        }
        return false;
    }
    
    /**
     * Creaates Funded Implication
     * TODO consider better separation. This shouldn't be in adapter class.
     */
    public FundedImplication createFundedImplication(double support, double confidence) {
        
        FundedImplication fimpl = new FundedImplication(support, confidence);
        
        for (int p = 0; p < antecedentClasses.length; p++) {
            fimpl.getAntecedents().add(getItem(antecedentClasses[p]));
        }
        
        for (int p = 0; p < succedentClasses.length; p++) {
            fimpl.getSuccedents().add(getItem(succedentClasses[p]));
        }

        return fimpl;
    }
    
    /**
     * See createFundedImplication() method.
     */
    public FundedAssociation createFundedAssociation(double support, double confidence) {
        
        FundedAssociation assoc = new FundedAssociation(support, confidence);
        
        for (int p = 0; p < antecedentClasses.length; p++) {
            assoc.getAntecedents().add(getItem(antecedentClasses[p]));
        }
        
        for (int p = 0; p < succedentClasses.length; p++) {
            assoc.getSuccedents().add(getItem(succedentClasses[p]));
        }

        return assoc;
    }    
    
    public String toString() {
        StringBuffer sb = new StringBuffer();
        for (int i = 0 ; i < items.size(); i++) {
            Item item = (Item) items.get(i);
            sb.append(item.getName() + " ");
            String[] names = item.getIntervalNames();
            for (int n = 0 ; n < names.length; n++) {
                sb.append(names[n] + " ");
            }
            sb.append("\n");
        }
        return sb.toString();
    }
    
}
